import Main from "../../Main";
import JoyStick from "../../../components/JoyStick/script/JoyStick";
import Player from "../../prefab/Player";
import Background from "./GameBackground";
import Stone from "../../prefab/Stone";
import GameEntities from "./GameEntities";
import FollowTargetCamera from "../../../components/Camera/FollowTargetCamera";
import SpeedyCamera from "../../../components/Camera/SpeedyCamera";

// Learn TypeScript:
//  - [Chinese] https://docs.cocos.com/creator/manual/zh/scripting/typescript.html
//  - [English] http://www.cocos2d-x.org/docs/creator/manual/en/scripting/typescript.html
// Learn Attribute:
//  - [Chinese] https://docs.cocos.com/creator/manual/zh/scripting/reference/attributes.html
//  - [English] http://www.cocos2d-x.org/docs/creator/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - [Chinese] https://docs.cocos.com/creator/manual/zh/scripting/life-cycle-callbacks.html
//  - [English] http://www.cocos2d-x.org/docs/creator/manual/en/scripting/life-cycle-callbacks.html

const { ccclass, property } = cc._decorator;

@ccclass
export default class GameScene extends cc.Component {

    @property({ type: cc.Node })
    joyStick: cc.Node = null
    @property({ type: Player })
    mainPlayer: Player = null
    @property({ type: cc.Camera })
    camera: cc.Camera = null
    @property({ type: Background })
    background: Background = null
    @property({ type: GameEntities })
    gameMap: GameEntities = null

    private _canTriggerBall: boolean = true
    public get canTriggerBall(): boolean {
        return this._canTriggerBall
    }
    public set canTriggerBall(b: boolean) {
        this._canTriggerBall = b
        this.joyStick.active = this.canTriggerBall
    }

    onLoad() {
        this._initPhysical()
        this._initPlayer()
    }

    start() {
        this.canTriggerBall = true
        this.joyStick.on(JoyStick.EvtStart, this._beginTrigger, this)
        this.joyStick.on(JoyStick.EvtUpdate, this._updateTrigger, this)
        this.joyStick.on(JoyStick.EvtReset, this._doTrigger, this)
        this.joyStick.on(JoyStick.EvtCancel, this._cancelTrigger, this)

        this.gameMap.initStones()
    }

    update(dt: number) {
        if (this.mainPlayer) {
            this.background.updatePlaterPos(this.mainPlayer)
            let speedLabel = cc.find("Canvas/UI/SpeedLabel").getComponent(cc.Label)
            speedLabel.string = "速度: " + this.mainPlayer.rigidBody.linearVelocity.mag().toFixed(2)
        }
    }


    _pause: boolean = false
    _slowDown: boolean = false
    _initPhysical() {
        let self = this
        let phyManager = cc.director.getPhysicsManager()
        phyManager.enabledAccumulator = true
        phyManager.enabled = true
        phyManager.gravity = cc.v2(0, -640)
        if (Main.DebugMode) {
            phyManager.debugDrawFlags = cc.PhysicsManager.DrawBits.e_aabbBit | cc.PhysicsManager.DrawBits.e_jointBit | cc.PhysicsManager.DrawBits.e_shapeBit
        }
        let _accumulator = phyManager["_accumulator"]
        if (phyManager.enabledAccumulator) {
            cc.find("Canvas/Main Camera").getComponent(FollowTargetCamera).autoUpdate = false
            let oldfunc: (dt: number) => void = phyManager["update"]

            phyManager["update"] = (dt: number) => {
                self._stepPhyics(dt)
            }
            /*
            phyManager["update"] = (dt: number) => {
                if (!phyManager.enabled) { return }
                let run = false

                if (self._pause) {
                    run = true
                } else if (self._slowDown) {
                    var world = phyManager["_world"]

                    dt = dt / 10

                    phyManager["emit"]('before-step')

                    phyManager["_steping"] = true
                    world.Step(dt, cc.PhysicsManager.VELOCITY_ITERATIONS, cc.PhysicsManager.POSITION_ITERATIONS)
                    phyManager["_steping"] = false

                    if (phyManager["debugDrawFlags"]) {
                        phyManager["_checkDebugDrawValid"]()
                        phyManager["_debugDrawer"].clear()
                        world.DrawDebugData()
                    }

                    phyManager["_syncNode"]()
                    run = true
                } else {
                    _accumulator += dt
                    if (_accumulator > cc.PhysicsManager.MAX_ACCUMULATOR) {
                        _accumulator = cc.PhysicsManager.MAX_ACCUMULATOR
                    }
                    while (_accumulator > cc.PhysicsManager.FIXED_TIME_STEP) {
                        run = true
                        _accumulator -= cc.PhysicsManager.FIXED_TIME_STEP
                    }

                    oldfunc.call(phyManager, dt)
                }
                if (run) {
                    cc.find("Canvas/Main Camera").getComponent(FollowTargetCamera).updataPosition(0)
                }
            }
            */
        }
    }
    _stepPhyics(dt: number) {
        let self = this
        let phyManager = cc.director.getPhysicsManager()

        if (self._pause) {
            return
        } else if (self._slowDown) {
            dt = dt / 20
        }

        var world = phyManager["_world"]
        if (!world || !phyManager.enabled) return;

        phyManager["emit"]('before-step');

        phyManager["_steping"] = true;

        var velocityIterations = cc.PhysicsManager.VELOCITY_ITERATIONS;
        var positionIterations = cc.PhysicsManager.POSITION_ITERATIONS;

        var FIXED_TIME_STEP = cc.PhysicsManager.FIXED_TIME_STEP;
        var MAX_ACCUMULATOR = cc.PhysicsManager.MAX_ACCUMULATOR;

        world.Step(dt, velocityIterations, positionIterations);

        if (phyManager.debugDrawFlags) {
            phyManager["_checkDebugDrawValid"]();
            phyManager["_debugDrawer"].clear();
            world.DrawDebugData();
        }

        phyManager["steping"] = false;

        var events = phyManager["_delayEvents"];
        for (var i = 0, l = events.length; i < l; i++) {
            var event = events[i];
            event.target[event.func].apply(event.target, event.args);
        }
        events.length = 0;

        phyManager["_syncNode"]();

        cc.find("Canvas/Main Camera").getComponent(FollowTargetCamera).updataPosition(0)

        if (self.mainPlayer) {
            self.mainPlayer.getComponent(cc.MotionStreak)["update"](0)
        }
    }

    _initPlayer() {
        let self = this
        cc.loader.loadRes("prefab/Player", cc.Prefab, (err: Error, res: cc.Prefab) => {
            let node = cc.instantiate(res)
            self.mainPlayer = node.getComponent(Player)
            node.setPosition(0, 150)
            self.gameMap.node.addChild(node)

            self.camera.getComponent(FollowTargetCamera).target = node
            self.camera.getComponent(SpeedyCamera).target = node.getComponent(cc.RigidBody)

            self.mainPlayer.node.on(Player.EvtBeginContact, self._beginContact, self)
            self.mainPlayer.node.on(Player.EvtPreSlove, self._preSolve, self)
        })
    }

    private _stickDirect: cc.Vec2 = cc.v2()
    private _stickPower: number = 0
    _beginTrigger() {
        this._slowDown = true
    }
    _updateTrigger(p: cc.Vec2, d: number) {
        this._stickDirect.set(p)
        this._stickPower = d
        this.mainPlayer.showForce(this._stickDirect, this._stickPower)
    }
    _doTrigger() {
        this._slowDown = false
        //this.canTriggerBall = false
        this.mainPlayer.trigger()
        let force = this._stickDirect.clone()
        force.mulSelf(this._stickPower)
        force.mulSelf(6400)
        this.mainPlayer.rigidBody.linearVelocity = cc.v2()
        this.mainPlayer.rigidBody.applyLinearImpulse(force, cc.Vec2.ZERO, true)
    }
    _cancelTrigger() {
        this._slowDown = false
        this.mainPlayer.showForce(null, 0)
    }

    _beginContact(contact: cc.PhysicsContact, selfCollider: cc.PhysicsCollider, otherCollider: cc.PhysicsCollider) {
        let stone = otherCollider.node.getComponent(Stone)
        let player = selfCollider.node.getComponent(Player)
        if (player) {
            if (stone) {
                contact.disabled = true
                stone.explosionMe()
                let force = player.node.getPosition().clone()
                force.subSelf(stone.node.getPosition())
                player.rigidBody.applyLinearImpulse(force.normalizeSelf().mulSelf(1500), cc.Vec2.ZERO, true)
            }
        }
    }

    _preSolve(contact: cc.PhysicsContact, selfCollider: cc.PhysicsCollider, otherCollider: cc.PhysicsCollider) {
        this.canTriggerBall = true
    }
}
